package com.netstar.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.content.Context;
import android.net.TrafficStats;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;

import com.netstar.library.NetStarApplication;
import com.netstar.xmlparser.ServerChannelHelper;

public class Utils {

	public static long getHours(long millis) {
		if (millis <= 0) {
			return 0;
		}

		return millis / 1000 / 3600;
	}

	public static long getMinutes(long millis) {
		if (millis <= 0) {
			return 0;
		}

		return millis / 1000 % 3600 / 60;
	}

	public static long getSeconds(long millis) {
		if (millis <= 0) {
			return 0;
		}
		return millis / 1000 % 60;
	}

	public static long getMillis(long millis) {
		if (millis <= 0) {
			return 0;
		}
		return millis % 1000;
	}

	public static String toMBLength(long bytes) {
		if (bytes <= 0) {
			return "0";
		}
		float f = (float) bytes / 1024 / 1024;
		return String.valueOf(subFloat(f));
	}

	public static String toMBLengthWith2(long bytes) {
		if (bytes <= 0) {
			return "0.00";
		}
		float f = (float) bytes / 1024 / 1024;
		return String.valueOf(subFloatWith2(f));
	}

	public static String parseLength(long bytes) {
		if (bytes < 0) {
			return "0B";
		} else if (bytes < 1024) {
			return bytes + "B";
		} else if (bytes < 1024 * 1024) {
			float f = (float) bytes / 1024;
			return subFloat(f) + "KB";
		} else if (bytes < 1024 * 1024 * 1024) {
			float f = (float) bytes / 1024 / 1024;
			return subFloat(f) + "MB";
		} else {
			float f = (float) bytes / 1024 / 1024 / 1024;
			return subFloat(f) + "GB";
		}
	}

	public static float subFloat(float f) {
		DecimalFormat decimalFormat = new DecimalFormat("#0.0");
		return Float.parseFloat(decimalFormat.format(f));
	}

	public static float subFloatWith2(float f) {
		DecimalFormat decimalFormat = new DecimalFormat("#0.00");
		return Float.parseFloat(decimalFormat.format(f));
	}

	public static final int MSG_NO_RESPONSE = 1;

	public static final int MSG_NETWORK_NOT_STABLE = 2;

	public static final int MSG_TIMEOUT = 3;

	public static final int MSG_START_TEST_SPEED = 4;

	public static final int MSG_TEST_END = 5;

	public static final int MSG_BEGIN_CONNECT = 6;

	public static final int MSG_UPDATE_UI = 7;

	private static final String SERVER = "http://www.qq.com/";

	private static final long UPDATE_INTERVAL = 1000;

	private static final int TEST_COUNT = 10;

	public static void performSpeedTest(Context context, final Handler handler) {
		new Thread() {

			@Override
			public void run() {
				InputStream is = null;
				HttpGet get = null;
				long sum = 0;
				long timeCost = 0;
				try {
					// Send out a timeout message delayed 10 seconds.
					handler.sendEmptyMessageDelayed(MSG_TIMEOUT, 10000);
					HttpClient client = new DefaultHttpClient();
					get = new HttpGet(SERVER);
					handler.sendEmptyMessage(MSG_BEGIN_CONNECT);
					HttpResponse response = client.execute(get);
					// Remove the timeout message
					handler.removeMessages(MSG_TIMEOUT);
					HttpEntity entity = response.getEntity();
					if (null == entity) {
						handler.sendEmptyMessage(MSG_NO_RESPONSE);
					} else {
						is = entity.getContent();
						if (null == is) {
							handler.sendEmptyMessage(MSG_NO_RESPONSE);
						} else {
							handler.sendEmptyMessage(MSG_START_TEST_SPEED);
							int bytesRead = -1;
							byte[] buffer = new byte[4096];
							long lastReadTime = SystemClock.uptimeMillis();
							int i = 0;
							while (i < TEST_COUNT && -1 != (bytesRead = is.read(buffer))) {
								timeCost += SystemClock.uptimeMillis() - lastReadTime;
								sum += bytesRead;
								Status status = new Status();
								status.setProp(sum, timeCost);
								Message message = Message.obtain(handler, MSG_UPDATE_UI, status);
								message.arg1 = i == TEST_COUNT - 1 ? 1 : 0;
								handler.sendMessageDelayed(message, i * UPDATE_INTERVAL);
								lastReadTime = SystemClock.uptimeMillis();
								i++;
							}
							// Perhaps never happen
							if (i != TEST_COUNT) {
								Status status = new Status();
								status.setProp(sum, timeCost);
								Message message = Message.obtain(handler, MSG_UPDATE_UI, status);
								message.arg1 = 1;
								handler.sendMessageDelayed(message, i * UPDATE_INTERVAL);
							}

							EvtLog.i("performSpeedTest", "totally read " + sum + " bytes, cost " + timeCost + " ms");
						}
					}
				} catch (Exception e) {
					handler.sendEmptyMessage(MSG_NETWORK_NOT_STABLE);
					handler.removeMessages(MSG_TEST_END);
					Status status = new Status();
					status.setProp(sum, timeCost);
					Message msg = Message.obtain(handler, MSG_TEST_END, status);
					msg.sendToTarget();
				} finally {
					if (null != get) {
						get.abort();
					}
					if (null != is) {
						try {
							is.close();
						} catch (IOException e) {
						}
					}
				}
			}
		}.start();

	}

	public static long getReceivedBytes(int uid) {
		long rx = TrafficStats.getUidRxBytes(uid);
		return rx >= 0 ? rx : 0;
	}

	public static long getSentBytes(int uid) {
		long tx = TrafficStats.getUidTxBytes(uid);
		return tx >= 0 ? tx : 0;
	}

	private static final Calendar sCalendar = Calendar.getInstance();

	private static final SimpleDateFormat sDayFormat = new SimpleDateFormat("yyyy-MM-dd");

	private static final SimpleDateFormat sMonthFormat = new SimpleDateFormat("yyyy-MM");

	/**
	 * As 2011-07-07.
	 */
	public static String getNowInDay() {
		return sDayFormat.format(new Date());
	}

	public static int getLeftDaysOfMonth() {
		Calendar calendar = sCalendar;
		calendar.setTimeInMillis(System.currentTimeMillis());
		int daysInMonth = calendar.getMaximum(Calendar.DAY_OF_MONTH);
		int date = calendar.get(Calendar.DATE);
		return daysInMonth - date;
	}

	public static int getGoneDaysOfMonth() {
		Calendar calendar = sCalendar;
		calendar.setTimeInMillis(System.currentTimeMillis());
		return calendar.get(Calendar.DATE);
	}

	public static String getLastDayOfMonth(String month) {
		try {
			Calendar calendar = sCalendar;
			Date date = sMonthFormat.parse(month);
			calendar.setTime(date);
			int max = calendar.getMaximum(Calendar.DAY_OF_MONTH);
			calendar.set(Calendar.DATE, max);
			return sDayFormat.format(calendar.getTime());
		} catch (ParseException e) {
			EvtLog.e("getLastDayOfMonth", "month is " + month + ", " + e.getMessage());
		}
		return null;
	}

	/**
	 * As 2011-07.
	 */
	public static String getNowInMonth() {
		return sMonthFormat.format(new Date());
	}

	public static String getNextMonth(String month) {
		try {
			Date date = sMonthFormat.parse(month);
			sCalendar.setTime(date);
			sCalendar.add(Calendar.MONTH, 1);
			return sMonthFormat.format(sCalendar.getTime());
		} catch (ParseException e) {
			EvtLog.e("getNextMonth", e.getMessage());
			return getNowInMonth();
		}
	}

	public static String getPrevMonth(String month) {
		try {
			Date date = sMonthFormat.parse(month);
			sCalendar.setTime(date);
			sCalendar.add(Calendar.MONTH, -1);
			return sMonthFormat.format(sCalendar.getTime());
		} catch (ParseException e) {
			EvtLog.e("getPrevMonth", e.getMessage());
			return getNowInMonth();
		}
	}

	public static String getDayForMillis(long time) {
		return sDayFormat.format(new Date(time));
	}

	public static String channelToCol(String channel) {
		if (null == channel) {
			return "_3g_gprs";
		}
		if (channel.startsWith("CMCC")) {
			return "_cmcc";
		} else if (channel.startsWith("ChinaUnicom")) {
			return "_unicom";
		} else if (channel.startsWith("ChinaNet")) {
			return "_china_net";
		} else if (channel.startsWith("WIFI")) {
			return "_wifi";
		}
		return "_3g_gprs";
	}

	public static long getMobileBytes() {
		return TrafficStats.getMobileRxBytes() + TrafficStats.getMobileTxBytes();
	}

	public static long getWifiBytes() {
		return TrafficStats.getTotalRxBytes() + TrafficStats.getTotalTxBytes() - getMobileBytes();
	}

	public static String generateChannelInfo(long data, long time) {
		return Utils.parseLength(data) + " " + Utils.getHours(time) + ":" + Utils.getMinutes(time);
	}

	private static void serializable(FileOutputStream fos, Object o) throws Exception {
		ObjectOutputStream oos = null;
		try {
			oos = new ObjectOutputStream(fos);
			oos.writeObject(o);
			oos.flush();
		} finally {
			if (oos != null) {
				try {
					oos.close();
				} catch (IOException e) {
				}
			}
		}
	}

	private static Object unSerializable(FileInputStream fis) throws Exception {
		ObjectInputStream ois = null;
		try {
			ois = new ObjectInputStream(fis);
			return ois.readObject();
		} finally {
			if (ois != null) {
				try {
					ois.close();
				} catch (IOException e) {
				}
			}
		}
	}

	@SuppressWarnings("unchecked")
	public static ArrayList<ServerChannelHelper.ServerChannelItem> parseFileToList(String fileName) {
		File file = NetStarApplication.CONTEXT.getFileStreamPath(fileName);
		ArrayList<ServerChannelHelper.ServerChannelItem> list = null;
		if (file.exists()) {
			FileInputStream fis = null;
			try {
				fis = NetStarApplication.CONTEXT.openFileInput(fileName);
				list = (ArrayList<ServerChannelHelper.ServerChannelItem>) Utils.unSerializable(fis);
			} catch (Exception e) {
				file.delete();
				EvtLog.e("parseFileToList", e.getMessage());
			} finally {
				if (null != fis) {
					try {
						fis.close();
					} catch (IOException e) {
					}
				}
			}
		}
		return list;
	}

	public static void saveListToFile(ArrayList<ServerChannelHelper.ServerChannelItem> list, String fileName) {
		FileOutputStream fos = null;
		try {
			fos = NetStarApplication.CONTEXT.openFileOutput(fileName, Context.MODE_PRIVATE);
			Utils.serializable(fos, list);
		} catch (Exception e) {
			EvtLog.e("saveListToFile", e.getMessage());
		} finally {
			if (null != fos) {
				try {
					fos.close();
				} catch (IOException e) {
				}
			}
		}

	}

}
